package com.oly.cms.web.controller;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.Writer;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import org.thymeleaf.TemplateEngine;
import org.thymeleaf.context.Context;
import org.thymeleaf.templatemode.TemplateMode;
import org.thymeleaf.templateresolver.ClassLoaderTemplateResolver;

import com.grace.common.config.GraceConfig;
import com.grace.common.core.domain.AjaxResult;
import com.grace.common.enums.GraceServerRoot;
import com.grace.common.exception.file.FileSizeLimitExceededException;
import com.grace.common.exception.file.InvalidExtensionException;
import com.grace.common.utils.file.FileUtils;
import com.oly.cms.common.enums.CategoryNodeTypeEnums;
import com.oly.cms.common.model.properties.OlyWebConfigProperties;
import com.oly.cms.common.utils.ZipUtils;
import com.oly.cms.common.utils.site.GenerateMapUtils;
import com.oly.cms.general.service.taglib.ArticleTag;
import com.oly.cms.general.service.taglib.CategoryTag;
import com.oly.cms.general.service.taglib.ConfigTag;
import com.oly.cms.web.config.OlyPagePrefix;
import com.oly.cms.web.service.impl.WebThemeServiceImpl;
import com.oly.cms.web.utils.WebUtils;

/** 远程操作本地主题接口
 *  可在配置指定IP访问
 */
@RestController
@RequestMapping("/web/theme")
public class WebThemeController extends CommonController {

    private static final Logger logger = LoggerFactory.getLogger(WebThemeController.class);
    @Autowired
    private WebThemeServiceImpl themeService;

    @Autowired
    private ConfigTag configTag;

    @Autowired
    private ArticleTag articleTag;

    @Autowired
    private CategoryTag categoryTag;

    /**
     * 主题文件上传
     * 
     * @param file
     * @param request
     * @return
     * @throws IOException
     * @throws InvalidExtensionException
     * @throws FileSizeLimitExceededException
     */
    @PostMapping("/uploadTheme")
    public AjaxResult uploadTheme(@RequestParam("themeFile") MultipartFile file, boolean cover,
            HttpServletRequest request) throws IOException, FileSizeLimitExceededException, InvalidExtensionException {
        return AjaxResult.success(themeService.uploadTheme(file, cover));
    }

    /**
     * 通过主题获取信息及配置
     * 
     * @param themeName
     * @return
     * @throws FileNotFoundException
     */
    @GetMapping("/getThemeSetting/{themeName}")
    public AjaxResult selectThemeSetting(@PathVariable("themeName") String themeName) {
        return AjaxResult.success(themeService.selectThemeConfigSetting(themeName));
    }

    /**
     * 通过主题获取信息及配置
     * 
     * @param themeName
     * @return
     * @throws FileNotFoundException
     */
    @GetMapping("/getThemeConfigForm/{themeName}")
    public AjaxResult selectThemeConfig(@PathVariable("themeName") String themeName) {
        try {
            return AjaxResult.success(themeService.selectThemeConfigForm(themeName));
        } catch (IOException e) {
            logger.info("获取主题表单失败:" + e.getMessage());
            return AjaxResult.error("获取主题表单失败:" + e.getMessage());
        }
    }

    /**
     * 删除主题
     * 
     * @param themeName
     * @return
     * @throws FileNotFoundException
     */
    @PostMapping("/deleteTheme")
    public AjaxResult deleteTheme(String themeName) throws FileNotFoundException {
        return AjaxResult.success(themeService.deleteThemeByName(themeName));
    }

    /**
     * 获取主题文件树
     * 
     * @param olyCode
     * @return
     */
    @GetMapping(value = "/getThemeTree/{olyCode}")
    public AjaxResult selectThemeList(@PathVariable("olyCode") String olyCode) {
        if (GraceConfig.getOnlyCode().equals(olyCode)) {
            return AjaxResult.success(themeService.selectThemeFileTree(""));
        } else {
            return AjaxResult.error("唯一编号不符");
        }

    }

    /**
     * 获取文件内容
     * 
     * @param path
     * @return
     */
    @GetMapping("/getThemeFileContent")
    public AjaxResult themeContent(String path) throws FileNotFoundException {
        final File file = Paths.get(GraceServerRoot.THEME_DIR.getWorkRoot(path)).toFile();
        if (!file.exists()) {
            return AjaxResult.error("文件不存在");
        }
        if (file.isDirectory()) {
            return AjaxResult.error("所选文件为文件夹！");
        }
        try {
            return AjaxResult.success(FileUtils.readFileContent(file.toPath()));
        } catch (IOException e) {
            logger.info("获取内容失败:" + e);
            return AjaxResult.error("获取内容失败:" + e.getMessage());
        }

    }

    /**
     * 文件上传
     * 
     * @param webName
     * @param path
     * @param fileContent
     * @return
     * @throws IOException
     */
    @PostMapping("/updateThemeFileContent/{webName}")
    public AjaxResult updateThemeFileContent(@PathVariable("webName") String webName, String path,
            String fileContent) {
        if (GraceConfig.getOnlyCode().equals(webName)) {
            try {
                FileUtils.saveContent(fileContent, GraceServerRoot.THEME_DIR.getWorkRoot(path));
                return AjaxResult.success("写入成功!");
            } catch (IOException e) {
                logger.info("写入内容失败:" + e);
                return AjaxResult.error("写入内容失败:" + e.getMessage());
            }
        } else {
            return AjaxResult.error("唯一编号不符");
        }
    }

    /**
     * 备份并下载
     * 
     * @param webName
     * @param themeName
     * @param request
     * @param response
     */
    @PostMapping("/themeDownload/{webName}/{themeName}")
    public void processDownload(@PathVariable("webName") String webName,
            @PathVariable("themeName") String themeName, HttpServletRequest request, HttpServletResponse response) {
        String rootPath = GraceServerRoot.THEME_DIR.getWorkRoot();
        String backTemplatesPath = Paths.get(rootPath, GraceServerRoot.THEME_TEMPLATE_DIR.getValue(), themeName)
                .toString();
        String backStaticPath = Paths.get(rootPath, GraceServerRoot.THEME_STATIC_DIR.getValue(), themeName).toString();
        String savePath = Paths.get(GraceServerRoot.BACK_DIR.getWorkRoot(webName + ".zip")).toString();
        ZipUtils.themeToZip(backTemplatesPath, backStaticPath, savePath, webName, true);
        int BUFFER_SIZE = 100000;
        InputStream in = null;
        OutputStream out = null;
        try {
            request.setCharacterEncoding("utf-8");
            response.setCharacterEncoding("utf-8");
            response.setContentType("application/octet-stream");
            File file = new File(savePath);
            response.setContentLength((int) file.length());
            response.setHeader("Accept-Ranges", "bytes");
            int readLength = 0;
            in = new BufferedInputStream(new FileInputStream(file), BUFFER_SIZE);
            out = new BufferedOutputStream(response.getOutputStream());

            byte[] buffer = new byte[BUFFER_SIZE];
            while ((readLength = in.read(buffer)) > 0) {
                byte[] bytes = new byte[readLength];
                System.arraycopy(buffer, 0, bytes, 0, readLength);
                out.write(bytes);
            }
            out.flush();

        } catch (Exception e) {
            logger.info("写入内容失败:" + e);
        } finally {
            if (in != null) {
                try {
                    in.close();
                } catch (IOException e) {
                    logger.info("关闭io异常:" + e);
                }
            }
            if (out != null) {
                try {
                    out.close();
                } catch (IOException e) {
                    logger.info("关闭io异常:" + e);
                }
            }
        }
    }

    @GetMapping("/getThemeNames")
    public AjaxResult getLocalThemes() {
        List<String> themeNames = WebUtils.listThemeNames();
        if (themeNames != null) {
            return success(themeNames);
        }
        return error("本地未安装任何主题!");
    }
    @PostMapping("/siteMapIndex/{themeName}")
    public AjaxResult buildSiteMapIndex(@PathVariable("themeName") String themeName) {
        String domain = configTag.getKeyDefaultEnum(themeName, OlyWebConfigProperties.DOMAIN);
        Map<String, Object> variables = new HashMap<>();
        variables.put("domain", domain);
        variables.put("categryPages",
                Math.ceil(categoryTag.selectCategoryNum(themeName, CategoryNodeTypeEnums.DEFAULT) / 5000));
        variables.put("articlePages", Math.ceil(articleTag.selectArticleNum(themeName) / 5000));
        String outFilePath = Paths
                .get(GraceServerRoot.THEME_DIR.getWorkRoot(GraceServerRoot.THEME_TEMPLATE_DIR.getValue()), themeName,
                        GraceServerRoot.SITE_DIR.getValue(), "siteMap_index.xml")
                .toString();
        generateFileWithThymeleafEngine(themeName, "siteMap_index", variables, outFilePath);
        return success();

    }
    @PostMapping("/siteMapRegular/{themeName}")
    public AjaxResult buildSiteMapRegular(@PathVariable("themeName") String themeName,List<String> urls) {
        String domain = configTag.getKeyDefaultEnum(themeName, OlyWebConfigProperties.DOMAIN);
        Map<String, Object> variables = new HashMap<>();
        variables.put("urls", urls);
        variables.put("domain", domain);
        String outFilePath = Paths
                .get(GraceServerRoot.THEME_DIR.getWorkRoot(GraceServerRoot.THEME_TEMPLATE_DIR.getValue()), themeName,
                        GraceServerRoot.SITE_DIR.getValue(), "regular.xml")
                .toString();
        generateFileWithThymeleafEngine(themeName, "regular", variables, outFilePath);
        return success();
    }

    /**
     * 手动渲染xml并填充
     * 依据主题 一键生成siteMap
     * 默认文件 主题/templates/site/regular.xml
     * 动态索引
     * 
     * @return
     */
    @PostMapping("/siteMapXml/{themeName}")
    @ResponseBody
    public AjaxResult siteMapXml(@PathVariable("themeName") String themeName) {
        // 传递参数 domain 文章页树 分类页数

        String basePath = Paths
                .get(GraceServerRoot.THEME_DIR.getWorkRoot(GraceServerRoot.THEME_TEMPLATE_DIR.getValue()), themeName,
                        GraceServerRoot.SITE_DIR.getValue())
                .toString();
        Map<String, List<String>> mnMap = new HashMap<>();
        List<String> em = new ArrayList<>();
        em.add("");
        // 主页
        mnMap.put(OlyPagePrefix.indexPage, em);
        // 分类页
        mnMap.put(OlyPagePrefix.categoriesPage, em);
        // 排行榜
        mnMap.put(OlyPagePrefix.rankPage, em);
        // 关于页
        mnMap.put(OlyPagePrefix.aboutPage, em);
        // 链接页
        mnMap.put(OlyPagePrefix.linksPage, em);
        // 反馈页
        mnMap.put(OlyPagePrefix.contactPage, em);
        GenerateMapUtils.generateBaiDuMap(basePath,
                configService.getKeyDefaultEnum(themeName, OlyWebConfigProperties.DOMAIN), mnMap, themeName,
                themeName);
        // 主页
        // 所有文章
        // 分类{单个分类 文章，所有分类}
        // 标签{单个标签 文章，所有标签}
        // 外链列表
        // 自定义页
        return success();
    }
    // 主索引
    // 静态索引固定
    // 动态索引固定
    // siteMap动态添加更新移除
    // 单独页面 index about links contact domain/sitemap/category/type/CLASSIFY
    // domain/sitemap/article/type/PHOTO 手动添加索引
    // 单独一个siteMap文件
    // 聚合页面 动态生成 domain/xxx/{page}/sitemap.xml
    // domain/sitemap/article/{page}.xml domain/sitemap/category/{page}.xml

    // ...

    public static void generateFileWithThymeleafEngine(String themeName, String templateName,
            Map<String, Object> variables, String outputPath) {
        // 初始化TemplateEngine
        TemplateEngine templateEngine = new TemplateEngine();

        // 设置TemplateResolver（这里使用类加载器作为模板源）
        ClassLoaderTemplateResolver resolver = new ClassLoaderTemplateResolver();
        resolver.setPrefix("templates/model/site/"); // 模板前缀，根据实际情况调整
        resolver.setSuffix(".xml"); // 模板后缀
        resolver.setTemplateMode(TemplateMode.XML);
        resolver.setCharacterEncoding("UTF-8");
        templateEngine.setTemplateResolver(resolver);

        // 创建和设置Context
        Context context = new Context();
        // 参数
        context.setVariables(variables);

        // 输出到文件
        try (Writer writer = Files.newBufferedWriter(Paths.get(outputPath))) {
            templateEngine.process(templateName, context, writer);
        } catch (IOException e) {
            // 处理异常
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        Map<String, Object> variables = new HashMap<>();
        variables.put("domain", "https://www.example.com");
        variables.put("categories", Arrays.asList("Category 1", "Category 2"));
        variables.put("listArticle", Arrays.asList(
                Map.of("title", "Article 1", "url", "https://www.example.com/article1"),
                Map.of("title", "Article 2", "url", "https://www.example.com/article2")));
        generateFileWithThymeleafEngine("default", "article.xml", variables, "D:\\test.xml");
    }

}
